import random
import torch

"""
    生成y=Xw+b+噪声
"""


def synthetic_data(w, b, num_examples):  # @save
    # torch.normal 生成符合高斯分布的数据
    # mean = 0,std = 1,size = (num_examples, len(w)) ---> 输出张量的形状。
    X = torch.normal(0, 1, (num_examples, len(w)))  # 1000 x 2

    y = torch.matmul(X, w) + b
    y += torch.normal(0, 0.01, y.shape)
    # y.reshape((-1, 1))，第二维度的大小为 1，第一个维度的大小自动推导
    return X, y.reshape((-1, 1))


"""
    生成器函数
"""


def data_iter(batch_size_, features_, labels_):
    num_examples = len(features_)  # 对于张量，len(任意维度的张量)返回第一个维度的大小

    # 创建一个list() -> list对象,range() -> 生成一系列连续的整数
    indices = list(range(num_examples))

    # 这些样本是随机读取的，没有特定的顺序
    random.shuffle(indices)

    # 0 batch_size batch_size*2 batch_size*3
    # 生成器函数,yield返回后会暂停函数执行，保留状态，调用next函数继续执行
    for i in range(0, num_examples, batch_size_):
        batch_indices = torch.tensor(indices[i: min(i + batch_size_, num_examples)])
        yield features_[batch_indices], labels_[batch_indices]


"""
    定义模型
"""


def linreg(X, w, b):  # @save
    """线性回归模型"""
    return torch.matmul(X, w) + b


features, labels = synthetic_data(torch.tensor([2, -3.4]), 4.2, 1000)

batch_size = 10  # 批次大小

# 遍历函数生成器
# for X, y in data_iter(batch_size, features, labels):
#     print(X, '\n', y, '\n')

w = torch.normal(0, 0.01, size=(2, 1), requires_grad=True)
b = torch.zeros(1, requires_grad=True)
